﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Workflow.ComponentModel.Design;
using System.ComponentModel.Design.Serialization;
using System.ComponentModel.Design;
using System.Drawing.Design;
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Serialization;
using System.IO;
using System.Xml;
using System.Workflow.Activities.Rules;
using System.Collections;
using System.Windows.Forms;
using System.Workflow.Activities;

namespace WfDesignControl
{
    public class WFLoader : WorkflowDesignerLoader
    {
        public string Xoml { set; get; }
        public string Rules { set; get; }
        public string Layout { set; get; }
        public TypeProvider TypeProvider { get; set; }

        public string XomlFile { set; get; }

        #region 重写方法

        protected override void Initialize()
        {
            base.Initialize();
            //该方法返回为该设计器加载程序提供的加载程序宿主。
            //如果尚未调用 BeginLoad，或者如果该设计器加载程序已被释放，
            //则该方法可能为 null
            IDesignerLoaderHost host = this.LoaderHost;

            //向设计面中加入服务
            if (host != null)
            {
                host.AddService(typeof(IMenuCommandService),
                    new WfMenuCommandService(host));

                host.AddService(typeof(IToolboxService),
                    new ToolboxService(host));

                //TypeProvider.AddAssemblyReference(typeof(string).Assembly.Location);
                //TypeProvider.AddAssembly(typeof(Activity).Assembly);
                //TypeProvider.AddAssembly(typeof(System.Workflow.Activities.CodeActivity).Assembly);
                //TypeProvider.AddAssembly(typeof(System.Workflow.Activities.SendActivity).Assembly);
                //TypeProvider.AddAssembly(typeof(SharedWorkflows.IBILLService).Assembly);
                //host.AddService(typeof(ITypeProvider), TypeProvider, true);

                TypeProvider typeProvider = new TypeProvider(host);
                typeProvider.AddAssemblyReference(typeof(string).Assembly.Location);
                typeProvider.AddAssembly(typeof(Activity).Assembly);
                typeProvider.AddAssembly(typeof(System.Workflow.Activities.CodeActivity).Assembly);
                typeProvider.AddAssembly(typeof(System.Workflow.Activities.SendActivity).Assembly);
                typeProvider.AddAssembly(typeof(CommonLibrary.Wf.InterFace.IBILLService).Assembly);
                host.AddService(typeof(ITypeProvider), typeProvider, true);
            }

        }

        public override void Dispose()
        {
            IDesignerLoaderHost host = LoaderHost;
            if (host != null)
            {
                host.RemoveService(typeof(IMenuCommandService));
                host.RemoveService(typeof(IToolboxService));
                host.RemoveService(typeof(ITypeProvider), true);
            }
            base.Dispose();
        }

        #region 没用的东西
        public override string FileName
        {
            get
            {
                return string.Empty;
            }
        }

        public override TextReader GetFileReader(string filePath)
        {
            return null;
        }

        public override TextWriter GetFileWriter(string filePath)
        {
            return null;
        }
        #endregion

        protected override void PerformLoad(IDesignerSerializationManager serializationManager)
        {
            if (string.IsNullOrEmpty(this.Xoml))
            {
                return;
            }
            Activity rootActivity = null;
            IDesignerHost designerHost = (IDesignerHost)GetService(typeof(IDesignerHost));
            WorkflowMarkupSerializer mySerializer = new WorkflowMarkupSerializer();

            try
            {
                if (!string.IsNullOrEmpty(Xoml))
                {
                    TextReader readerXoml = new StringReader(this.Xoml);
                    using (XmlReader xomlReader = XmlTextReader.Create(readerXoml))
                    {
                        rootActivity = mySerializer.Deserialize(xomlReader) as Activity;
                    }
                    if (rootActivity == null)
                    {
                        MessageBox.Show("解析文件失败！");
                        return;
                    }

                }
                if (!string.IsNullOrEmpty(this.Rules))
                {
                    TextReader readerRules = new StringReader(this.Rules);
                    using (XmlReader xmlReader = XmlTextReader.Create(readerRules))
                    {
                        object obj = mySerializer.Deserialize(xmlReader);
                        RuleDefinitions rule = obj as RuleDefinitions;
                        rootActivity.SetValue(RuleDefinitions.RuleDefinitionsProperty, rule);
                    }
                }
            }
            catch (WorkflowMarkupSerializationException ex)
            {
                MessageBox.Show(ex.Message);
            }

            if (rootActivity != null && designerHost != null)
            {
                //通过DesignHost将Activy添加
                AddObjectGraphToDesignerHost(designerHost, rootActivity);
            }
            designerHost.Activate();
        }

        protected override void PerformFlush(IDesignerSerializationManager manager)
        {

        }

        //在设计器加载完成时调用
        /// <summary>
        /// Note: In case of state machine workflows we need to load the layout from the layout file in the 
        /// OnEndLoad method. This is because the layout file is applied to the designer components which are
        /// created in PerformLoad and are available only on the OnEndLoad method
        /// </summary>
        /// <param name="successful"></param>
        /// <param name="errors"></param>
        protected override void OnEndLoad(bool successful, ICollection errors)
        {
            base.OnEndLoad(successful, errors);

            if (!string.IsNullOrEmpty(this.Layout))
            {
                TextReader readerLayout = new StringReader(this.Layout);
                using (XmlReader xmlReader = XmlTextReader.Create(readerLayout))
                {
                    IList loaderrors = null;
                    LoadDesignerLayout(xmlReader, out loaderrors);
                }
            }
        }

        #endregion

        #region 私有

        //将活动添加到工作流设计器宿主
        private static void AddObjectGraphToDesignerHost(IDesignerHost designerHost, Activity activity)
        {
            string fullClassName = activity.GetType().FullName;
            string rootSiteName = (fullClassName.LastIndexOf('.') != -1) ? fullClassName.Substring(fullClassName.LastIndexOf('.') + 1) : fullClassName;

            designerHost.Container.Add(activity, rootSiteName);
            if (activity is CompositeActivity)
            {
                foreach (Activity childActivity in GetNestedActivities(activity as CompositeActivity))
                    designerHost.Container.Add(childActivity, childActivity.QualifiedName);
            }
        }

        //创建嵌套子活动的数组
        private static Activity[] GetNestedActivities(CompositeActivity compositeActivity)
        {
            if (compositeActivity == null)
                throw new ArgumentNullException("compositeActivity");

            ArrayList nestedActivities = new ArrayList();
            Queue compositeActivities = new Queue();
            //队列
            compositeActivities.Enqueue(compositeActivity); //添加

            while (compositeActivities.Count > 0)
            {
                CompositeActivity currentCompositeActivity = (CompositeActivity)compositeActivities.Dequeue();
                foreach (Activity activity in currentCompositeActivity.Activities)
                {
                    nestedActivities.Add(activity);
                    if (activity is CompositeActivity)
                        compositeActivities.Enqueue(activity);
                }
            }
            return (Activity[])nestedActivities.ToArray(typeof(Activity));
        }

        #endregion

        //从设计器宿主中移除活动
        public static void DestroyObjectGraphFromDesignerHost(IDesignerHost designerHost, Activity activity)
        {
            if (designerHost == null)
                throw new ArgumentNullException("designerHost");
            if (activity == null)
                throw new ArgumentNullException("activity");

            designerHost.DestroyComponent(activity);

            if (activity is CompositeActivity)
            {
                foreach (Activity activity2 in GetNestedActivities(activity as CompositeActivity))
                    designerHost.DestroyComponent(activity2);
            }
        }

        /// <summary>
        /// mlh 
        /// </summary>
        /// <param name="activitys"></param>
        /// <returns></returns>
        public static bool Validate(CompositeActivity activitys)
        {
            foreach (Activity item in activitys.Activities)
            {
                if (item is EventDrivenActivity)
                {
                    if (item.Description == "")
                    {
                        MessageBox.Show(item.Name + "的描述不能为空");
                        return false; 
                    }
                }
                else if (item is StateActivity)
                {
                    if (Validate(item as CompositeActivity) == false)
                    {
                        //MessageBox.Show(item.Name + "的描述不能为空");
                        return false;
                    }
                }
            }
            return true;

        }

        public void Save()
        {
            IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost));
            Activity rootActivity = host.RootComponent as Activity;
            WorkflowMarkupSerializer mySerializer = new WorkflowMarkupSerializer();

            if (host != null && host.RootComponent != null && rootActivity != null)
            {
                using (XmlTextWriter xmlWriter = new XmlTextWriter(this.XomlFile, Encoding.UTF8))
                {
                    mySerializer.Serialize(xmlWriter, rootActivity);
                }
            }

            string rulesFile = Path.Combine(Path.GetDirectoryName(this.XomlFile),
                Path.GetFileNameWithoutExtension(this.XomlFile) + ".rules");
            using (XmlTextWriter rulesWriter = new XmlTextWriter(rulesFile, Encoding.UTF8))
            {
                WorkflowMarkupSerializer xomlSerializer = new WorkflowMarkupSerializer();
                object obj = rootActivity.GetValue(RuleDefinitions.RuleDefinitionsProperty);
                mySerializer.Serialize(rulesWriter, obj);
            }

            // Need to save the layout in case of State Machine Workflow
            string layoutFile = Path.Combine(Path.GetDirectoryName(this.XomlFile),
                Path.GetFileNameWithoutExtension(this.XomlFile) + ".layout");
            ActivityDesigner rootdesigner = host.GetDesigner(rootActivity) as
                ActivityDesigner;
            if (rootdesigner == null) return;
            using (XmlTextWriter layoutwriter = new XmlTextWriter(layoutFile, Encoding.UTF8))
            {
                IList errors = null;
                SaveDesignerLayout(layoutwriter, rootdesigner, out errors);
                layoutwriter.Close();
            }

        }

    }
}
